#ifndef JLIB_GRAPHICS_NODES_PAINTNODE_H
#define JLIB_GRAPHICS_NODES_PAINTNODE_H

#include "node.h"
#include "../opengl/shader.h"

namespace jlib {


struct PaintNode : Node {

  using Node::Node;

  void draw (const mat4 &pv, const mat4 &p, const mat4 &v, const mat4 &m) override;

  void point (const vec2 &point, const rgba &color, float size = 1.0F) noexcept;
  void points (const vec2 *points, const rgba &color, unsigned int count, float size = 1.0F) noexcept;
  void points (const vec2 *points, const rgba *colors, unsigned int count, float size = 1.0F) noexcept;

  void line (const vec2 &point1, const vec2 &point2, const rgba &color, float width = 1.0F) noexcept;
  void line (const vec2 &point1, const vec2 &point2, const rgba &color1, const rgba &color2, float width = 1.0F) noexcept;
  void lines (const vec2 *point, const rgba &color, unsigned int count, GLenum mode = GL_LINES, float width = 1.0F) noexcept;
  void lines (const vec2 *point, const rgba *colors, unsigned int count, GLenum mode = GL_LINES, float width = 1.0F) noexcept;

  void bezier (const vec2 &point1, const vec2 &point2, const vec2 &point3, const rgba &color, float width = 1.0F, unsigned int segments = 100) noexcept;
  void bezier (const vec2 &point1, const vec2 &point2, const vec2 &point3, const vec2 &point4, const rgba &color, float width = 1.0F, unsigned int segments = 100) noexcept;

  void circle (const vec2 &center, float radius, const rgba &color) noexcept;
  void circle (const vec2 &center, float radius, const rgba &color, float width) noexcept;

  void oval (const vec2 &center, float radiusX, float radiusY, const rgba &color) noexcept;
  void oval (const vec2 &center, float radiusX, float radiusY, const rgba &color, float width) noexcept;

  void rect (const box2 &rect, const rgba &color) noexcept;
  void rect (const box2 &rect, const rgba &color, float width) noexcept;

  void roundRect (const box2 &rect, const vec4 &radius/*{leftDown, rightDown, rightUp, leftUp}*/, const rgba &color) noexcept;
  void roundRect (const box2 &rect, const vec4 &radius, const rgba &color, float width) noexcept;
  void roundRect (const box2 &rect, const vec4 &radiusX, const vec4 &radiusY, const rgba &color) noexcept;
  void roundRect (const box2 &rect, const vec4 &radiusX, const vec4 &radiusY, const rgba &color, float width) noexcept;

  void ring (const vec2 &origin, const vec2 &radius/*{inner, outer}*/, const rgba &color, float startAngle, float endAngle) noexcept;
  void ring (const vec2 &origin, const vec2 &radiusX, const vec2 &radiusY, const rgba &color, float startAngle, float endAngle) noexcept;

  void polygon (const vec2 *vertices, unsigned int count, const rgba &color) noexcept;
  void polygon (const vec2 *vertices, unsigned int count, const rgba &color, float width) noexcept;
  void polygon (const vec2 *vertices, const rgba *colors, unsigned int count) noexcept;
  void polygon (const vec2 *vertices, const rgba *colors, unsigned int count, float width) noexcept;

  inline void setTransform (const mat4 &tr) noexcept { this->_userTransform = tr; }
  inline void addTransform (const mat4 &tr) noexcept { this->_userTransform *= tr; }

  inline void setBlendFunc (GLenum src, GLenum dst) noexcept { this->_srcFactor = src; this->_dstFactor = dst; };
  inline GLenum getSrcBlendFunc () const noexcept { return this->_srcFactor; }
  inline GLenum getDstBlendFunc () const noexcept { return this->_dstFactor; }

  inline void setDrawer (const std::function<void(PaintNode*)> &drawer) noexcept { this->_drawer = drawer; }
  inline void setCurveAccuracy (unsigned int accuracy) { this->_accuracy = accuracy; }

  enum {
    u_tex = 0,
    u_pvm = 0,
    u_color = 1,
    a_position = 0,
    a_color = 1,
  };

protected:
  Shader *prepareUColorShader () noexcept;
  Shader *prepareVColorShader () noexcept;

  Objptr<Shader> _ucolorShader;
  Objptr<Shader> _vcolorShader;
  std::function<void(PaintNode*)> _drawer;

  mat4 _baseTransform;
  mat4 _userTransform;

  GLenum _srcFactor {GL_SRC_ALPHA};
  GLenum _dstFactor {GL_ONE_MINUS_SRC_ALPHA};

  unsigned int _accuracy {3};

  static const char *UColorVShader;
  static const char *UColorFShader;
  static const std::string UColorShaderName;

  static const char *VColorVShader;
  static const char *VColorFShader;
  static const std::string VColorShaderName;

}; // struct Node


} // namespace jlib


#endif // JLIB_GRAPHICS_NODES_PAINTNODE_H
